package com.neveu.android.ds.socketmessenger;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

import android.util.Log;

public class NetServent {

	Socket clientSock;
	ServerSocket serverSock;
	private String loopbackIP;
	private int connectPort;
	private PrintWriter pw;
	private MessageListener msgListener;
	private BufferedReader in;

	
	public NetServent(String loopbackIP, final int listenPort, int clientPort)
	{
		this.loopbackIP = loopbackIP;
		this.connectPort = clientPort;
		

		new Thread(new Runnable() {
			public void run()
			{
				try {
					serverSock = new ServerSocket(listenPort);
				}catch(IOException e){
					System.err.println("Could not establish listening socket on port " + listenPort);
				}
				
				while(true)
				{
					try {
						clientSock = serverSock.accept();
						readInput();
					}catch(IOException e) {
						/* this is caught whether there is a legitimate socket issue, or if serverSock
						 * has been explicitly closed. Either way, readInput() is not reached, which is what we want.
						 */
	//					System.err.println("Could not establish listening socket on port ");
					}
				}
			}}).start();
	}
	
	private class ConnectThread implements Runnable
	{
		public void run()
		{
			try{
				clientSock = new Socket(loopbackIP, connectPort);
				readInput();
				
			} catch (UnknownHostException e) {
	            System.err.println("Don't know about host: " + loopbackIP + ".");
	        } catch (IOException e) {
	            System.err.println("Couldn't get I/O for "
	                               + "the connection to: " + loopbackIP + ".");
	        }
			
		}
		
	}
	
	
	public void connect(int port)
	{
		connectPort = port;
		
//		if(clientSock == null || !clientSock.isConnected())
//		{
			new Thread(new ConnectThread()).start();
//		}
		
	}
	
	public void sendMessage(String msg)
	{
		if(!clientSock.isConnected())
			return;
		
		if(pw == null)
		{
			try{
				pw = new PrintWriter(clientSock.getOutputStream(), true);
	        } catch (IOException e) {
	        	System.err.println("Could not get socket output stream");
	        }
		}
		
		pw.println(msg);
	}
	
	public synchronized void readInput()
	{
		String inStr = "";
		
		try{
			in = new BufferedReader(
				    new InputStreamReader(
				    		clientSock.getInputStream()));

//			while(clientSock.isBound())

			/* How to nicely interrupt this blocking call when we wish to exit?? */
				while((inStr = in.readLine()) != null)
				{
					
					if(msgListener != null)
						msgListener.receiveMessage(inStr + "\n");
					else
						System.out.println(inStr);
				}

				in.close();
				
		}catch (IOException e) {
//			System.err.println(e.getMessage());
		}
		finally{
		}
	}
		

	
	public void disconnect()
	{
		try{
//			in.close();
			pw.close();
			clientSock.close();
			serverSock.close();
		}catch(Exception e)
		{
			Log.d("NetServent.disconnect", e.getMessage());
		}
	}
	
	public void setMessageListener(MessageListener ml)
	{
		msgListener = ml;
	}
}
